Skip to content

Method: parse(Name, Token)

1: package de.fhdw.wtf.parser;
2:
3: import java.util.Collection;
4: import java.util.Vector;
5:
6: import de.fhdw.wtf.common.ast.Attribute;
7: import de.fhdw.wtf.common.ast.Constructor;
8: import de.fhdw.wtf.common.ast.Name;
9: import de.fhdw.wtf.common.ast.Operation;
10: import de.fhdw.wtf.common.ast.type.ByNameState;
11: import de.fhdw.wtf.common.ast.type.ClassModifier;
12: import de.fhdw.wtf.common.ast.type.ClassType;
13: import de.fhdw.wtf.common.ast.type.RegularClassType;
14: import de.fhdw.wtf.common.ast.type.Type;
15: import de.fhdw.wtf.common.ast.type.TypeProxy;
16: import de.fhdw.wtf.common.exception.parser.AbstractParserException;
17: import de.fhdw.wtf.common.exception.parser.NoCurlyBracketOpenException;
18: import de.fhdw.wtf.common.exception.parser.NoEqualException;
19: import de.fhdw.wtf.common.exception.parser.NoPlusSymbolException;
20: import de.fhdw.wtf.common.exception.parser.NoSemicolonException;
21: import de.fhdw.wtf.common.stream.TokenStream;
22: import de.fhdw.wtf.common.token.IdentifierToken;
23: import de.fhdw.wtf.common.token.Token;
24:
25: /**
26: * Parser to parse a given {@link TokenStream}.
27: *
28: * TODO -> Duplicate code. See ExceptionClassParser. As a first try just copied ClassParser to ExceptionClassParser and
29: * RegularClassParser. Think about how to split them.
30: */
31: public final class RegularClassParser {
32:         
33:         /**
34:          * Tokenstream.
35:          */
36:         private final TokenStream stream;
37:         
38:         /**
39:          * Collection for exceptions.
40:          */
41:         private final Collection<AbstractParserException> exceptions;
42:         
43:         /**
44:          * Constructor of {@link RegularClassParser}.
45:          *
46:          * @param stream
47:          * tokenstream
48:          * @param exceptions
49:          * collection for exceptions
50:          */
51:         private RegularClassParser(final TokenStream stream, final Collection<AbstractParserException> exceptions) {
52:                 this.stream = stream;
53:                 this.exceptions = exceptions;
54:         }
55:         
56:         /**
57:          * Creates a {@link RegularClassParser}-Object.
58:          *
59:          * @param stream
60:          * tokenstream
61:          * @param exceptions
62:          * collection for exceptions
63:          * @return the {@link RegularClassParser}-Object.
64:          */
65:         protected static RegularClassParser create(final TokenStream stream,
66:                         final Collection<AbstractParserException> exceptions) {
67:                 return new RegularClassParser(stream, exceptions);
68:         }
69:         
70:         /**
71:          * Parses a Class with <code>name</code> as the class name from this.stream. This method expects the first Token in
72:          * the stream to be an EqualToken. This method calls an operation to parse the Attributes and ClassModifiers. If one
73:          * of the Tokens in the stream is unexpected, an AbstractParserException will be thrown.
74:          *
75:          * @param name
76:          * : Name of Class.
77:          * @param firstToken
78:          * : First token of class.
79:          * @throws AbstractParserException
80:          * AbstractParserException
81:          * @return ClassType
82:          */
83:         protected ClassType parse(final Name name, final Token firstToken) throws AbstractParserException {
84:                 try {
85:                         ParserUtils.requireAndRemoveEqualToken(this.stream);
86:                 } catch (final NoEqualException e) {
87:                         throw e;
88:                 }
89:                 
90:                 final Collection<Attribute> attributes = new Vector<>();
91:                 final Collection<ClassModifier> modifiers = new Vector<>();
92:                 final Collection<ClassType> subTypes = new Vector<>();
93:                 final Collection<Operation> operations = new Vector<>();
94:                 final Collection<Type> superTypes = new Vector<>();
95:                 final Collection<Constructor> constructors = new Vector<>();
96:                 final ClassType classResult =
97:                                 RegularClassType.create(
98:                                                 name,
99:                                                 modifiers,
100:                                                 attributes,
101:                                                 superTypes,
102:                                                 operations,
103:                                                 constructors,
104:                                                 firstToken,
105:                                                 subTypes);
106:                 try {
107:                         classResult.getSuperTypes().addAll(this.parseSuperTypes());
108:                         ParserUtils.requireAndRemoveCurlyBracketOpenToken(this.stream);
109:                 } catch (final NoCurlyBracketOpenException e) {
110:                         this.exceptions.add(e);
111:                         // Don't skip to next semicolon because you may find it behind the class so that
112:                         // you produce more exceptions as necessary.
113:                 }
114:•                while (this.stream.hasNext() && !this.checkClassEnd() && !(this.stream.peek().isEndToken())) {
115:                         final Token currentToken = this.stream.peek();
116:•                        if (currentToken.isIdentifierToken()) {
117:                                 try {
118:                                         final IdentifierToken token = ParserUtils.requireAndRemoveIdentifier(this.stream);
119:                                         this.parseClassElement(
120:                                                         classResult,
121:                                                         constructors,
122:                                                         attributes,
123:                                                         operations,
124:                                                         token.stringRepresentation(),
125:                                                         classResult,
126:                                                         token);
127:                                 } catch (final NoSemicolonException e) {
128:                                         throw e;
129:                                 } catch (final AbstractParserException e) {
130:                                         this.exceptions.add(e);
131:                                         ParserUtils.skipToSemicolonToken(this.stream);
132:                                         continue;
133:                                 }
134:•                        } else if (currentToken.isBracketOpenToken()) {
135:                                 this.parseConstructor(currentToken, constructors, classResult);
136:                         } else {
137:                                 ParserUtils.requireAndRemoveCurlyBracketCloseToken(this.stream);
138:                         }
139:                 }
140:                 modifiers.addAll(ClassModifierParser.create(this.stream, this.exceptions).parse(classResult));
141:                 classResult.setLastToken(this.stream.peek());
142:                 return classResult;
143:         }
144:         
145:         /**
146:          * Parses a constructor.
147:          *
148:          * @param firstToken
149:          * firstToken.
150:          * @param constructors
151:          * the list of constructors for classResult.
152:          * @param owner
153:          * the owner class of the constructor.
154:          * @throws AbstractParserException
155:          * if the syntax is not correct.
156:          */
157:         private void parseConstructor(final Token firstToken,
158:                         final Collection<Constructor> constructors,
159:                         final ClassType owner) throws AbstractParserException {
160:                 constructors.add(ConstructorParser.create(this.stream, this.exceptions).parse(firstToken, owner));
161:         }
162:         
163:         /**
164:          * Parses a series of tokens and returns the a list of {@link TypeProxy} . If the series of tokens does not match
165:          * the grammar an Exception will be thrown.
166:          *
167:          * @return super types
168:          * @throws AbstractParserException
169:          * {@link NoPlusSymbolException}: if there are some {@link IdentifierToken}s or an
170:          * {@link IdentifierToken} followed by an {@link de.fhdw.wtf.common.token.symbols.CurlyBracketOpenToken}
171:          * with no symbol between, than there is a PlusSymbol missing. {@link NoCurlyBracketOpenException}: If
172:          * it ist not a {@link NoPlusSymbolException} it must be a {@link NoCurlyBracketOpenException}.
173:          *
174:          */
175:         private Collection<TypeProxy> parseSuperTypes() throws AbstractParserException {
176:                 final Collection<TypeProxy> superTypes = new Vector<>();
177:                 
178:                 tryPossibleExceptions(this.stream.copy());
179:                 
180:                 while (this.stream.hasNext() && this.stream.peek().isIdentifierToken()) {
181:                         final NameParser nameParser = NameParser.createNameParser(this.stream);
182:                         final Name currentSuperTypeName = nameParser.parse();
183:                         
184:                         ParserUtils.requireAndRemovePlusSymbol(this.stream);
185:                         final ByNameState byName = ByNameState.create(currentSuperTypeName);
186:                         final TypeProxy typeProxy = TypeProxy.create(currentSuperTypeName.getFirstToken(), byName);
187:                         typeProxy.setLastToken(currentSuperTypeName.getLastToken());
188:                         superTypes.add(typeProxy);
189:                 }
190:                 return superTypes;
191:         }
192:         
193:         /**
194:          * Trys if there are any excpetions with missing + or {. In the case of missing { it is necessary to start the
195:          * parsing again from the first identifier. For example: Class:class=attribute:String;};
196:          *
197:          * @param copy
198:          * - a copy of the origin tokenStream
199:          * @throws AbstractParserException
200:          * {@link NoPlusSymbolException} and {@link NoCurlyBracketOpenException}.
201:          */
202:         private static void tryPossibleExceptions(final TokenStream copy) throws AbstractParserException {
203:                 final Token firstPosition = copy.peek();
204:                 
205:                 try {
206:                         while (copy.hasNext() && copy.peek().isIdentifierToken()) {
207:                                 final NameParser nameParser = NameParser.createNameParser(copy);
208:                                 nameParser.parse();
209:                                 ParserUtils.requireAndRemovePlusSymbol(copy);
210:                         }
211:                 } catch (final NoPlusSymbolException e) {
212:                         if (copy.hasNext() && (copy.peek().isIdentifierToken() || copy.peek().isCurlyBracketOpenToken())) {
213:                                 throw e;
214:                         } else {
215:                                 throw NoCurlyBracketOpenException.create(firstPosition);
216:                         }
217:                 }
218:         }
219:         
220:         /**
221:          * Parses a series of Tokens and creates attribute or operation. The name it is <code>name</code>. The result will
222:          * be add to <code>attributes</code> or <code>operations</code>. The first {@link Token} is <code>firstToken</code>.
223:          * be <code>attributeName</code>.
224:          *
225:          * @param classResult
226:          * the class that is being parsed at the moment.
227:          *
228:          * @param attributes
229:          * attributes
230:          * @param operations
231:          * operations
232:          * @param constructors
233:          * constructors
234:          * @param name
235:          * name of attribute or operation
236:          * @param firstToken
237:          * firstToken
238:          * @throws AbstractParserException
239:          * AbstractParserException
240:          */
241:         private void parseClassElement(final ClassType classResult,
242:                         final Collection<Constructor> constructors,
243:                         final Collection<Attribute> attributes,
244:                         final Collection<Operation> operations,
245:                         final String name,
246:                         final ClassType containingType,
247:                         final IdentifierToken firstToken) throws AbstractParserException {
248:                 ParserUtils.requireAndRemoveColonToken(this.stream);
249:                 final Token nextToken = this.stream.peek();
250:                 if (nextToken.isDoubleSquareBracketOpenToken()) {
251:                         this.stream.removeFirst();
252:                         operations
253:                                         .add(OperationParser.create(this.stream, this.exceptions).parse(name, containingType, firstToken));
254:                 } else {
255:                         attributes.add(AttributeParser.create(this.stream, this.exceptions).parse(name, firstToken));
256:                 }
257:                 
258:         }
259:         
260:         /**
261:          * Returns true if the next Token of this.stream is a CurlyBracketCloseToken, otherwise false.
262:          *
263:          * @return Boolean
264:          */
265:         private boolean checkClassEnd() {
266:                 if (!(this.stream.peek().isCurlyBracketCloseToken())) {
267:                         return false;
268:                 }
269:                 this.stream.removeFirst();
270:                 return true;
271:         }
272: }